﻿using System;
using IrcDotNet;
using System.ComponentModel;
using System.Collections;
using System.Collections.ObjectModel;
using System.Threading;

namespace IrcDotNet.Service
{
    public class Server
    {
        #region Private Members
        /// <summary>
        /// The IrcClient used for connect to a server.
        /// </summary>
        IrcClient client;
        #endregion

        #region Public Properties
        /// <summary>
        /// Name of the Server.
        /// </summary>
        public string Name { get { return client.ServerName; } }

        /// <summary>
        /// Is the server currently connected
        /// </summary>
        public bool IsConnected { get { return client.IsRegistered; } }

        /// <summary>
        /// Channel attached to the Server.
        /// </summary>
        public Channel Channel { get; private set; }
        #endregion

        #region Public Methods
        public Server()
        {
            this.client = new IrcClient();
            this.client.FloodPreventer = new IrcStandardFloodPreventer(4, 2000);
            Channel = new Channel(client);
        }

        public void Dispose()
        {
            client.Dispose();
        }

        /// <summary>
        /// Synchronous connexion to a server.
        /// </summary>
        /// <param name="serverAddress"></param>
        /// <param name="nickName"></param>
        /// <param name="userName"></param>
        /// <param name="realName"></param>
        /// <returns>True if the connection have been established, 
        /// False if you get a timeout on the registration.</returns>
        public bool Connect(string serverAddress,
            string nickName, string userName, string realName)
        {
            using (var connectionEvent = new ManualResetEvent(false))
            {
                EventHandler<EventArgs> connected = (s, e) =>
                { connectionEvent.Set(); };
                client.Registered += connected;

                client.Connect(serverAddress, new IrcUserRegistrationInfo()
                {
                    NickName = nickName,
                    UserName = userName,
                    RealName = realName
                });

                if (!connectionEvent.WaitOne(20000))
                {
                    client.Registered -= connected;
                    return false;
                }
                else
                {
                    client.Registered -= connected;
                    return true;
                }
            }
        }

        /// <summary>
        /// Synchronous disconnexion from a server
        /// </summary>
        /// <param name="comment"></param>
        /// <returns>True if the disconnexion is acknowledge by the server, 
        /// False if you get a timeout on the acknowledge.</returns>
        /// <remarks>Your are disconnected even if you get a timeout.</remarks>
        public bool Disconnect(string comment)
        {
            using (var disconnectionEvent = new ManualResetEvent(false))
            {
                EventHandler<EventArgs> disconnected = (s, e) =>
                { disconnectionEvent.Set(); };
                client.Disconnected += disconnected;

                client.Quit(10000, comment);

                if (!disconnectionEvent.WaitOne(10000))
                {
                    client.Disconnected -= disconnected;
                    return false;
                }
                else
                {
                    client.Disconnected -= disconnected;
                    return true;
                }
            }
        }

        /// <summary>
        /// Send a message to a specified User.
        /// </summary>
        /// <param name="user"></param>
        /// <param name="message"></param>
        public void Whisp(string user, string message)
        {
            client.LocalUser.SendMessage(user, message);
        }

        /// <summary>
        /// Get the nickname of users of this server.
        /// </summary>
        /// <returns></returns>
        public IEnumerable ListUser()
        {
            foreach (IrcUser user in client.Users)
            {
                yield return user.NickName;
            }
        }
        #endregion
    }
}
